using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using QuestFramework;
using QuestFramework.UI;
using QuestFramework.Debug;

namespace QuestFramework
{
    public class TestGame : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        ControllerInputPrompt prompter;
        WindowManager windowManager;
        FPSCounter fpsCount;
        DebugConsole debugConsole;
        WorldGrid floorGrid;
        Input gameInput;
        Camera gameCamera;
        ConsoleMessage debugInfo;
        Cube player;
        //Cube dummy1;
        //Cube dummy2;

        SpriteBatch textBatch;
        SpriteFont textFont;


        public TestGame()
        {
            // Setup Game
            this.IsFixedTimeStep = false;
            Content.RootDirectory = "Content";

            // Setup Graphics Device
            graphics = new GraphicsDeviceManager(this);
            graphics.SynchronizeWithVerticalRetrace = false;
            graphics.PreferredBackBufferWidth = 1280; //1920; //1280;
            graphics.PreferredBackBufferHeight = 720; //1080; //720;
            graphics.ApplyChanges();
        }

        protected override void Initialize()
        {
            gameInput = Input.Instance;
            gameCamera = Camera.Instance;
            gameCamera.Initialize(this.GraphicsDevice.Viewport.AspectRatio, new Vector3(5000.0f, 10000.0f, 30000.0f), new Vector3(0.0f, 0.0f, 0.0f));
            gameCamera.MoveSpeed = 20.0f;

            textBatch = new SpriteBatch(this.GraphicsDevice);
            textFont = this.Content.Load<SpriteFont>("Fonts\\Pericles");

            floorGrid = new WorldGrid(10000, 10000, 1000);
            floorGrid.Initialize(this.GraphicsDevice);

            debugInfo = new ConsoleMessage();
            debugInfo.Position = new Vector2(20, 20);
            debugInfo.Scale = 1.0f;
            debugInfo.TextColor = Color.Black;

            debugConsole = new DebugConsole();
            debugConsole.Initialize();
            debugConsole.Messages.Add(debugInfo);

            fpsCount = new FPSCounter();
            fpsCount.Initialize(new Vector2(1200.0f, 10.0f), textBatch, textFont);

            player = new Cube(500f, Color.White);
            player.Initialize(this.GraphicsDevice);

            /*
            dummy1 = new Cube(500f, Color.Red);
            dummy1.Initialize(this.GraphicsDevice);
            dummy1.MoveCubeHorizontally(2);

            dummy2 = new Cube(500f, Color.Green);
            dummy2.Initialize(this.GraphicsDevice);
            dummy2.MoveCubeHorizontally(-2);
            */

            // Instantiate Game Components - TODO: Eliminate game components
            prompter = new ControllerInputPrompt(this, Buttons.Y);
            windowManager = new WindowManager(this);
            this.Components.Add(windowManager);
            this.Components.Add(prompter);

            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            gameInput.Update();
            gameCamera.Update();

            // Allows the game to exit
            if (gameInput.CurrentP1State.Buttons.Back == ButtonState.Pressed
                || gameInput.CurrentKeyboardState.IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }

            // Only Allow Camera Movement When Dialog Is Not Visible
            if (!windowManager.dialogWindow.Visible)
            {
                PerformCameraMovement();
                PerformCharacterMovement();
            }

            // Test - If A Was Pressed, We Don't Need To Show The Prompt
            if ((gameInput.CurrentP1State.Buttons.Y == ButtonState.Pressed 
                    && !(gameInput.PreviousP1State.Buttons.Y == ButtonState.Pressed))
                || (gameInput.CurrentKeyboardState.IsKeyDown(Keys.Y)
                    && !gameInput.PreviousKeyboardState.IsKeyDown(Keys.Y)))
            {
                    prompter.Hide();
            }

            // Test - Allow The Prompt To Become Visible Again When B Is Pressed
            if ((gameInput.CurrentP1State.Buttons.B == ButtonState.Pressed 
                    && !(gameInput.PreviousP1State.Buttons.B == ButtonState.Pressed))
                || (gameInput.CurrentKeyboardState.IsKeyDown(Keys.B)
                    && !gameInput.PreviousKeyboardState.IsKeyDown(Keys.B)))
            {
                    prompter.Show();
            }

            // Dialog Controls
            // Test - Start Conversation Logic And Display Conversation
            if ((gameInput.CurrentP1State.Buttons.X == ButtonState.Pressed
                    && !(gameInput.PreviousP1State.Buttons.X == ButtonState.Pressed))
                || (gameInput.CurrentKeyboardState.IsKeyDown(Keys.X)
                    && !gameInput.PreviousKeyboardState.IsKeyDown(Keys.X))
                || (gameInput.CurrentKeyboardState.IsKeyDown(Keys.X))
                    && !(gameInput.PreviousKeyboardState.IsKeyDown(Keys.X)))
            {
                windowManager.dialogWindow.Show(1);
            }

            if (windowManager.dialogWindow.Visible)
            {
                // Test - Move Conversation Selector Down
                if ((gameInput.CurrentP1State.DPad.Down == ButtonState.Pressed
                        && !(gameInput.PreviousP1State.DPad.Down == ButtonState.Pressed))
                    || (gameInput.CurrentP1State.ThumbSticks.Left.Y < 0
                        && gameInput.PreviousP1State.ThumbSticks.Left.Y == 0)
                    || (gameInput.CurrentKeyboardState.IsKeyDown(Keys.Down)
                        && !gameInput.PreviousKeyboardState.IsKeyDown(Keys.Down)))
                {
                    windowManager.dialogWindow.NextResponse();
                }

                // Test - Move Conversation Selector Up
                if ((gameInput.CurrentP1State.DPad.Up == ButtonState.Pressed
                        && !(gameInput.PreviousP1State.DPad.Up == ButtonState.Pressed))
                    || (gameInput.CurrentP1State.ThumbSticks.Left.Y > 0
                        && gameInput.PreviousP1State.ThumbSticks.Left.Y == 0)
                    || (gameInput.CurrentKeyboardState.IsKeyDown(Keys.Up)
                        && !gameInput.PreviousKeyboardState.IsKeyDown(Keys.Up)))
                {
                    windowManager.dialogWindow.PreviousResponse();
                }

                // Test - Select Conversation Response
                if ((gameInput.CurrentP1State.Buttons.A == ButtonState.Pressed
                        && !(gameInput.PreviousP1State.Buttons.A == ButtonState.Pressed))
                    || (gameInput.CurrentKeyboardState.IsKeyDown(Keys.Enter)
                        && !gameInput.PreviousKeyboardState.IsKeyDown(Keys.Enter)))
                {
                    windowManager.dialogWindow.SubmitResponse();
                }
            }

            debugConsole.Messages.Remove(debugInfo);

            debugInfo.Text = "Position: (X: " + gameCamera.Position.X.ToString()
                + " Y: " + gameCamera.Position.Y.ToString()
                + " Z: " + gameCamera.Position.Z.ToString()
                + " )\r\nTarget: (X: " + gameCamera.Target.X.ToString()
                + " Y: " + gameCamera.Target.Y.ToString()
                + " Z: " + gameCamera.Target.Z.ToString() 
                + " )\r\nMouse: (X: " + gameInput.CurrentMouseState.X.ToString()
                + " Y: " + gameInput.CurrentMouseState.Y.ToString()
                + ")";

            debugConsole.Messages.Add(debugInfo);
            fpsCount.Update(gameTime);

            floorGrid.Update();
            player.Update();

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            // Clear Graphics Device For Re-Draw
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            // Draw Background
            floorGrid.Draw(this.GraphicsDevice);

            // Draw "Characters"
            //dummy1.Draw(this.GraphicsDevice);
            //dummy2.Draw(this.GraphicsDevice);
            player.Draw(this.GraphicsDevice);

            // Draw 2D Last
            debugConsole.Draw(textBatch, textFont);
            fpsCount.Draw(gameTime);
            this.windowManager.dialogWindow.Draw(gameTime);

            // Include Remaining Game Components ANd Commit Draw
            base.Draw(gameTime);
        }

        #region Entry Point
        static void Main(string[] args)
        {
            using (TestGame game = new TestGame())
            {
                game.Run();
            }
        }
        #endregion

        private void PerformCameraMovement()
        {
            // Forward/Backward Camera Movement
            if ((gameInput.CurrentP1State.DPad.Up == ButtonState.Pressed)
                || (gameInput.CurrentP1State.ThumbSticks.Left.Y > 0)
                || (gameInput.CurrentKeyboardState.IsKeyDown(Keys.Up) && gameInput.CurrentKeyboardState.IsKeyUp(Keys.RightShift)))
            {
                gameCamera.Position += gameCamera.LookAxis * gameCamera.MoveSpeed;
            }

            if ((gameInput.CurrentP1State.DPad.Down == ButtonState.Pressed)
                || (gameInput.CurrentP1State.ThumbSticks.Left.Y < 0)
                || (gameInput.CurrentKeyboardState.IsKeyDown(Keys.Down) && gameInput.CurrentKeyboardState.IsKeyUp(Keys.RightShift)))
            {
                gameCamera.Position -= gameCamera.LookAxis * gameCamera.MoveSpeed;
            }

            //Up/Down Camera Movement
            if (gameInput.CurrentKeyboardState.IsKeyDown(Keys.Down) && gameInput.CurrentKeyboardState.IsKeyDown(Keys.RightShift))
            {
                gameCamera.Position -= gameCamera.UpAxis * gameCamera.MoveSpeed;
            }

            if (gameInput.CurrentKeyboardState.IsKeyDown(Keys.Up) && gameInput.CurrentKeyboardState.IsKeyDown(Keys.RightShift))
            {
                gameCamera.Position += gameCamera.UpAxis * gameCamera.MoveSpeed;
            }

            // Left/Right Camera Movement
            if ((gameInput.CurrentP1State.DPad.Right == ButtonState.Pressed)
                || (gameInput.CurrentP1State.ThumbSticks.Left.X > 0)
                || (gameInput.CurrentKeyboardState.IsKeyDown(Keys.Right)))
            {
                gameCamera.Position += gameCamera.RightAxis * gameCamera.MoveSpeed;
            }

            if ((gameInput.CurrentP1State.DPad.Left == ButtonState.Pressed)
                || (gameInput.CurrentP1State.ThumbSticks.Left.X < 0)
                || (gameInput.CurrentKeyboardState.IsKeyDown(Keys.Left)))
            {
                gameCamera.Position -= gameCamera.RightAxis * gameCamera.MoveSpeed;
            }

            // Camera Rotation (Only Up/Down and Left/Right)
            if (gameInput.CurrentMouseState.X >= gameInput.PreviousMouseState.X && gameInput.CurrentMouseState.RightButton == ButtonState.Pressed)
            {
                gameCamera.RotationY -= 0.0001f;

                if (gameCamera.RotationY < 0)
                    gameCamera.RotationY += 6.28318531f;
            }

            if (gameInput.CurrentMouseState.X <= gameInput.PreviousMouseState.X && gameInput.CurrentMouseState.RightButton == ButtonState.Pressed)
            {
                gameCamera.RotationY += 0.0001f;

                if (gameCamera.RotationY >= 6.28318531f)
                    gameCamera.RotationY -= 6.28318531f;
            }

            if (gameInput.CurrentMouseState.Y >= gameInput.PreviousMouseState.Y && gameInput.CurrentMouseState.RightButton == ButtonState.Pressed)
            {
                gameCamera.RotationX -= 0.0001f;
            }

            if (gameInput.CurrentMouseState.Y <= gameInput.PreviousMouseState.Y && gameInput.CurrentMouseState.RightButton == ButtonState.Pressed)
            {
                gameCamera.RotationX += 0.0001f;
            }

            if (gameInput.CurrentMouseState.RightButton == ButtonState.Released)
            {
                gameCamera.RotationX = 0f;
                gameCamera.RotationY = 0f;
            }

        }

        private void PerformCharacterMovement()
        {
            if (gameInput.CurrentKeyboardState.IsKeyDown(Keys.NumPad6))
            {
                player.MoveAcrossX(1);
            }

            if (gameInput.CurrentKeyboardState.IsKeyDown(Keys.NumPad4))
            {
                player.MoveAcrossX(-1);
            }

            if (gameInput.CurrentKeyboardState.IsKeyDown(Keys.NumPad8))
            {
                player.MoveAcrossZ(-1);
            }

            if (gameInput.CurrentKeyboardState.IsKeyDown(Keys.NumPad2))
            {
                player.MoveAcrossZ(1);
            }


        }
    }
}
